home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / What's New? / Software Development Kits / Mac OS USB DDK / MacOS USB DDK 1.0b4 / NeptuneDDK / Examples / SerialBox / ShimSerialUART.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-26  |  30.3 KB  |  1,274 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ShimSerialUART.c
  3.  
  4.     Contains:    Routines for controlling an 8250, 16450, or 16550 UART
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1994-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. #include    <Gestalt.h>
  14. #include    <LowMem.h>
  15. #include    <Memory.h>
  16.  
  17. #include    "ShimSerialInternal.h"
  18. #include    "SerialBox.h"
  19.  
  20.  
  21.  
  22.  
  23. #define DebugMessage(x) SysDebugStr(x)
  24. //#define DebugMessage(x) 
  25.  
  26. //#define TraceMessage(i,x) { static local_enable = i; if (local_enable) USBExpertStatus(0, x, 0); local_enable = local_enable; }
  27. //#define TraceMessage(i,x) { static local_enable = i; if (local_enable) SysDebugStr(x); local_enable = local_enable; }
  28. #define TraceMessage(i,x) 
  29.  
  30.  
  31. //    masks for getting & setting serial config info
  32. #define kSerConfigBaudMask            0x03FF
  33. #define kSerConfigLenMask            0x0C00
  34. #define kSerConfigParityMask        0x3000
  35. #define kSerConfigStopMask            0xC000
  36.  
  37.  
  38.  
  39.  
  40.  
  41. //////////////////////////////////////////////////////////////////////////////////////
  42. //
  43. //    B_Prime
  44. //
  45. //    this is the driver prime routine, called from the device manager in response to a _Read or _Write.
  46. //
  47.  
  48. OSErr    B_Read(ShimSerialGlobals * globals,
  49.                 IOCommandID    ioCommandID,
  50.                 IOParam * pb)
  51. {
  52. #pragma unused (ioCommandID)
  53.     OSErr    err;
  54.     
  55.     
  56.     TraceMessage(0,"\pEntering B_Read");
  57.     //    initialize actual count read
  58.     pb->ioActCount = 0;
  59.     
  60.     //    make sure we've something to read or write
  61.  
  62.     err = (OSErr)((pb->ioReqCount) ? 1 : noErr);
  63.     
  64.  
  65.     if ( err )
  66.         {
  67.  
  68.         //    if we didn't find our globals, return readErr;
  69.  
  70.         if ( !globals ) 
  71.             return readErr;
  72.  
  73.         //    attempt to fill read request immediately
  74.         //    from any pending data in the input buffer
  75.  
  76.         err = B_FillReadRequest(globals, pb);
  77.  
  78.  
  79.         //    ••• DO WE WANT TO KEEP DATA AFTER THE MODEM IS GONE?
  80.  
  81.         //    if read request unsatisfied and we have no uart (card
  82.         //    was physically removed, etc.) then we better bail out
  83.         //    now with a readErr rather than leave the client hanging
  84.         
  85.         // TODO:  What happens when our device disappears?
  86.  
  87. //        if ( !globals->uartRegs ) 
  88. //            return readErr; 
  89.  
  90.         //    otherwise if the request didn't complete, we set
  91.         //    this request as our new current read pb
  92.  
  93. //        if ( err > noErr )
  94. //            {
  95. //            globals->pbIn = pb;
  96. //            globals->pbInID = ioCommandID;
  97. //            }
  98.  
  99.         //    if software or hardware flow control are in effect
  100.         //    we prime input mechanism according to buffer levels
  101.         //    (otherwise, input is enabled and the pb will be
  102.         //    treated as input characters arrive from the uart)
  103.  
  104.         B_InputFlowControl(globals);
  105.         }
  106.  
  107.     //    return result to asm routine which will decide whether
  108.     //    to rts or jioDone...  no, our logic does not support
  109.     //    immediate primes (neither does the scc serial driver)
  110.  
  111.     return err;
  112. }
  113.  
  114.  
  115. OSErr    B_Write(ShimSerialGlobals * globals,
  116.                 IOCommandID    ioCommandID,
  117.                 IOParam *    pb)
  118. {
  119. #pragma unused (globals, ioCommandID)
  120.     OSErr                            err;
  121.     
  122.     
  123.     TraceMessage(0,"\pEntering B_Write");
  124.     
  125.     //    initialize actual count written
  126.     pb->ioActCount = 0;
  127.     
  128.     //    make sure we've something to read or write
  129.  
  130.     err = (OSErr)((pb->ioReqCount) ? 1 : noErr);
  131.     
  132.     
  133.     if ( err )
  134.         {
  135.  
  136.         err = USBSerialWrite(pb);
  137. #ifdef NOTYET
  138.         //    if we didn't find our globals, return writErr;
  139.         //    -OR-
  140.         //    if we have no uart (card was physically removed, etc.)
  141.         //    then there's no use in trying, there won't be any transmit
  142.         //    buffer empty interrupts, so just return writErr now...
  143.  
  144.         if ((!globals) ) 
  145.             return writErr; 
  146.  
  147.         //    otherwise set this request as our current write pb
  148.  
  149. //        globals->pbOut = pb;
  150. //        globals->pbOutID = ioCommandID;
  151.  
  152.         //    turn on write buffer empty interrupts to prime our write mechanism
  153.         
  154.         B_EnableOutput(globals);
  155. #endif   //NOTYET
  156.         }
  157.  
  158.     //    return result to asm routine which will decide whether
  159.     //    to rts or jioDone...  no, our logic does not support
  160.     //    immediate primes (neither does the scc serial driver)
  161.  
  162.     return(err);
  163. }
  164.  
  165.  
  166.  
  167.  
  168. //////////////////////////////////////////////////////////////////////////////////////
  169. //
  170. //    B_SerReset
  171. //
  172. //    serial driver reset control call.
  173. //
  174.  
  175. OSErr B_SerReset(ShimSerialGlobals * globals, UInt16 config)
  176. {
  177.     UInt16                            baudRate;
  178.     unsigned char                    len;
  179.     unsigned char                    parity;
  180.     unsigned char                    stop;
  181.  
  182.  
  183.     TraceMessage(1,"\pEntering B_SerReset");
  184.         
  185.     
  186.     switch (config & kSerConfigBaudMask)
  187.         {
  188.         case baud300: baudRate = 300; break;
  189.         case baud600: baudRate = 600; break;
  190.         case baud1200: baudRate = 1200; break;
  191.         case baud1800: baudRate = 1800; break;
  192.         case baud2400: baudRate = 2400; break;
  193.         case baud3600: baudRate = 3600; break;
  194.         case baud4800: baudRate = 4800; break;
  195.         case baud7200: baudRate = 7200; break;
  196.         case baud9600: baudRate = 9600; break;
  197.         case baud19200: baudRate = 19200; break;
  198.         case baud38400: baudRate = 38400; break;
  199.         case baud57600: baudRate = 57600; break;
  200.         default: baudRate = 57600; break;
  201.         }
  202.     
  203.     switch (config & kSerConfigLenMask)
  204.         {
  205.         case data5: len = kLen5Bits; break;
  206.         case data6: len = kLen6Bits; break;
  207.         case data7: len = kLen7Bits; break;
  208.         case data8: len = kLen8Bits; break;
  209.         default: len = kLen8Bits; break;
  210.         }
  211.     
  212.     switch (config & kSerConfigParityMask)
  213.         {
  214.         case noParity: parity = kParNone; break;
  215.         case oddParity: parity = kParOdd; break;
  216.         case evenParity: parity = kParEven; break;
  217.         default: parity = kParNone; break;
  218.         }
  219.     
  220.     switch (config & kSerConfigStopMask)
  221.         {
  222.         case stop10: stop = kStop1Bit; break;
  223.         case stop15: stop = kStop1_5Bits; break;
  224.         case stop20: stop = kStop2Bits; break;
  225.         default: stop = kStop1Bit; break;
  226.         }
  227.     
  228.     //    reset the baud rate on the chip
  229.  
  230.     B_SetBaudRate(globals, baudRate);
  231.  
  232.     //    reset the other values
  233.  
  234.     globals->lenParStop = (UInt8)(len + parity + stop);
  235.  
  236.     B_SetLenParStop(globals, globals->lenParStop);
  237.  
  238.     return(noErr);
  239. }
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246. //////////////////////////////////////////////////////////////////////////////////////
  247. //
  248. //    B_SetBuffer
  249. //
  250. //    select and initialize the serial input buffer.
  251. //
  252. //
  253. OSErr B_SetBuffer(ShimSerialGlobals * globals, Ptr newBuf, UInt16 bufLen)
  254. {
  255.     OSErr                            err;
  256.     long                            result;
  257.     Boolean                            vmPresent;
  258.     
  259.     
  260.     TraceMessage(1,"\pEntering B_SetBuffer");
  261.     
  262.     //  check for presence of virtual memory
  263.     err = Gestalt(gestaltVMAttr,&result);
  264.     vmPresent = ((err == noErr) && (result >= gestaltVMPresent));
  265.     
  266.     //  un-hold any previous input buffer
  267.     if (vmPresent && globals->inBufPtr && (globals->inBufPtr != globals->builtInBuffer))
  268.         UnholdMemory(globals->inBufPtr,globals->inBufLen);
  269.     
  270.     //    assign our local buffer as the default
  271.     globals->inBufPtr = globals->builtInBuffer;
  272.     globals->inBufLen = kBuiltInBufferSize;
  273.     
  274.     //    reset buffer indexes
  275.     globals->inBufStartIndex = 0;
  276.     globals->inBufEndIndex = 0;
  277.     
  278.     
  279.     //    a non-zero buffer length means use client buffer
  280.     //    a zero buffer length means use the default buffer
  281.     
  282.     if (bufLen && newBuf)
  283.     {
  284.         //  we need to make sure the buffer stays in physical memory and
  285.         //  doesn't get paged out to disk so our interrupt routines can
  286.         //  safely read and write to it
  287.         if (vmPresent)
  288.         {
  289.             err = HoldMemory(newBuf,bufLen);
  290.             if (err != noErr)
  291.                 return err;
  292.         }
  293.         
  294.         //    assign client buffer
  295.         globals->inBufPtr = (UInt8 *) newBuf;
  296.         globals->inBufLen = bufLen;
  297.     }
  298.     
  299.     return(noErr);
  300. }
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308. //////////////////////////////////////////////////////////////////////////////////////
  309. //
  310. //    B_SetSerShk
  311. //
  312. //    process the csSerHShake & csSerHShakeDTR control calls for input & output flow control.
  313. //
  314. //
  315. void B_SetSerShk(ShimSerialGlobals * globals, SerShk *shkNew, UInt16 csCode)
  316. {
  317.     TraceMessage(1,"\pEntering B_SetSerShk");
  318.     
  319.     //
  320.     //    set new cts value
  321.     //
  322.  
  323.     globals->serShk.fCTS = shkNew->fCTS;
  324.  
  325.     //
  326.     //    copy over new xon / xoff characters
  327.     //
  328.  
  329.     globals->serShk.xOn = shkNew->xOn;
  330.     globals->serShk.xOff = shkNew->xOff;
  331.  
  332.     //
  333.     //    handle any change in software output flow control
  334.     //
  335.  
  336.     if ( globals->serShk.fXOn != shkNew->fXOn )
  337.         {
  338.         //
  339.         //    set new software output flow control value
  340.         //    if we are turning off output flow control then
  341.         //    we must re-enable output if it was suppressed
  342.         //
  343.         
  344.         if ( !(globals->serShk.fXOn = shkNew->fXOn) )
  345.             B_EnableOutput(globals);
  346.         }
  347.  
  348.  
  349.     //    copy over the errs & evts options fields
  350.     //    notice we do _nada_ with the events (no _PostEvent, etc.)
  351.     
  352.     globals->serShk.errs = shkNew->errs & (parityErr | hwOverrunErr | framingErr);
  353.     globals->serShk.evts = shkNew->evts;
  354.  
  355.  
  356.     //    handle any change in software input flow control
  357.  
  358.     if ( globals->serShk.fInX != shkNew->fInX )
  359.         {
  360.         //
  361.         //    assign new software input flow control value
  362.         //    if we are turning off input flow control then
  363.         //    we must send an xon _if_ an xoff has been sent
  364.         //    (if we are turning it on, it will activate on
  365.         //    the next character received)
  366.         //
  367.         
  368.         if ( !(globals->serShk.fInX = shkNew->fInX) )
  369.             B_SendXOn(globals, false);
  370.         }
  371.  
  372.  
  373.     //    if csCode is newer kSERDHandshake,
  374.     //    take account of the fDTR field
  375.  
  376.     if ( csCode == kSERDHandshake )
  377.         {
  378.         
  379.         //
  380.         //    handle any change in hardware input flow control
  381.         //
  382.  
  383.         if ( globals->serShk.fDTR != shkNew->fDTR )
  384.             {
  385.             //
  386.             //    assign new hardware input flow control value
  387.             //    if we are turning it on, go handle it now.
  388.             //    if turning it off, make sure to re-assert dtr!
  389.             //
  390.  
  391.             globals->serShk.fDTR = shkNew->fDTR;
  392.             if ( globals->serShk.fDTR )
  393.                 B_InputFlowControl(globals);
  394.             else
  395.                 B_EnableInput(globals, true);
  396.             }
  397.         }
  398. }
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405. //////////////////////////////////////////////////////////////////////////////////////
  406. //
  407. //    B_SendXOn
  408. //
  409. //
  410. void B_SendXOn(ShimSerialGlobals * globals, Boolean always)
  411. {
  412.     TraceMessage(1,"\pEntering B_SendXOn");
  413.     
  414.     if (    always || (globals->serStat.xOffSent & xOffWasSent) )
  415.         {
  416.         globals->serStat.xOffSent &= (Byte)(~xOffWasSent);
  417.         globals->xOnOffChar = globals->serShk.xOn;
  418.         B_EnableOutput(globals);
  419.         }        
  420. }
  421.  
  422.  
  423.  
  424.  
  425.  
  426. //////////////////////////////////////////////////////////////////////////////////////
  427. //
  428. //    B_SendXOff
  429. //
  430. //
  431. void B_SendXOff(ShimSerialGlobals * globals, Boolean always)
  432. {
  433.     TraceMessage(1,"\pEntering B_SendXOff");
  434.     
  435.     if (    always || 
  436.             !(globals->serStat.xOffSent & xOffWasSent))
  437.         {
  438.         globals->serStat.xOffSent |= xOffWasSent;
  439.         globals->xOnOffChar = globals->serShk.xOff;
  440.         B_EnableOutput(globals);
  441.         }
  442. }
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449. //////////////////////////////////////////////////////////////////////////////////////
  450. //
  451. //    B_SerStatus
  452. //
  453. //    status routine fills in the SerStaRec record -- see inside mac vol. ii, serial drivers
  454. //
  455. //
  456. void B_SerStatus(ShimSerialGlobals * globals, SerStaRec *statRec)
  457. {
  458.     TraceMessage(0,"\pEntering B_SerStatus");
  459.     
  460.     //    get & reset cumErrs
  461.     
  462.     statRec->cumErrs = globals->serStat.cumErrs;
  463.     globals->serStat.cumErrs = 0;
  464.  
  465.     //    has an xOff been sent to stop input?
  466.  
  467.     statRec->xOffSent = globals->serStat.xOffSent;  
  468.  
  469.     //    is there a pending read request? 
  470.  
  471.     statRec->rdPend = (globals->pbIn != nil);
  472.  
  473.     //    is there a pending write request?
  474.  
  475.     statRec->wrPend = (globals->pbOut != nil);
  476.  
  477.     //    cts & xOff output flow control hold flags
  478.  
  479.     // TODO: return the state of CTSHold?
  480.     statRec->ctsHold = true; // !(globals->uartRegs->MSR & kCTSCompliment);
  481.  
  482.     statRec->xOffHold = globals->serStat.xOffHold;  
  483. }
  484.  
  485.  
  486.  
  487.  
  488.  
  489. //////////////////////////////////////////////////////////////////////////////////////
  490. //
  491. //    B_SerGetBuf
  492. //
  493. //    status routine computes & returns the number of bytes pending in the receive buffer 
  494. //
  495. //
  496. UInt32 B_SerGetBuf(ShimSerialGlobals * globals)
  497. {
  498.     SInt32                            count;
  499.     
  500.     TraceMessage(0,"\pEntering B_SerGetBuf");
  501.     
  502.     count = ((SInt32)globals->inBufEndIndex - (SInt32)globals->inBufStartIndex);
  503.     
  504.     if ( count < 0 ) 
  505.         count += globals->inBufLen;
  506.             
  507.     return count;
  508. }
  509.  
  510.  
  511. //////////////////////////////////////////////////////////////////////////////////////
  512. //
  513. //    B_EnableDTR
  514. //
  515. void B_EnableDTR(ShimSerialGlobals * globals, Boolean enable)
  516. {
  517. #pragma unused (globals)
  518.     USBSetDTRState(enable);
  519. }
  520.  
  521.  
  522. //////////////////////////////////////////////////////////////////////////////////////
  523. //
  524. //    B_EnableRTS
  525. //
  526. void B_EnableRTS(ShimSerialGlobals * globals, Boolean enable)
  527. {
  528. #pragma unused (globals)
  529.     USBSetRTSState(enable);
  530. }
  531.  
  532.  
  533.  
  534.  
  535. //////////////////////////////////////////////////////////////////////////////////////
  536. //
  537. //    B_SetBreak
  538. //
  539. void B_SetBreak(ShimSerialGlobals * globals, Boolean setBreak)
  540. {
  541. #pragma unused (globals)
  542.     USBSetBreakState(setBreak);
  543. }
  544.  
  545.  
  546.  
  547. //////////////////////////////////////////////////////////////////////////////////////
  548. //
  549. //    B_SetLenParStop
  550. //
  551. void B_SetLenParStop(ShimSerialGlobals * globals, UInt8 lenParStop )
  552. {
  553.     UInt8    parity;
  554. #pragma unused (globals)
  555.     
  556.     USBSetStopBits((lenParStop & kStop2Bits) ? 1 : 0);
  557.     USBSetDataBits(lenParStop & 0x03);
  558.     
  559.     switch (lenParStop & 0x38){
  560.         case kParNone:  parity = 0; break;
  561.         case kParEven:  parity = 1; break;
  562.         case kParOdd:      parity = 2; break;
  563.         case kParLow:      parity = 3; break;        // I guessed -- is mark hi or low?
  564.         case kParHigh:  parity = 4; break;        // I guessed -- is space hi or low?
  565.     }
  566.     USBSetParityBits(parity);
  567. }
  568.  
  569.  
  570.  
  571. //////////////////////////////////////////////////////////////////////////////////////
  572. //
  573. //    B_SetBaudRate
  574. //
  575. //    this is currently based upon a hardwired uart internal clock speed of 1.8432mhz
  576. //    which appears to be industry standard.  i guess that's what we'll use...
  577. //
  578.  
  579. UInt16 B_SetBaudRate(ShimSerialGlobals * globals, UInt32 baudRate)
  580. {
  581.     UInt16                    divisor;
  582.     
  583.     //    validate the requested baud rate
  584.     if ( baudRate )
  585.         {
  586.         if ( baudRate > kMaxBaudRate )        //    ••• CHANGE FOR 115 & 230K Baud!
  587.             baudRate = kMaxBaudRate;
  588.             
  589.         globals->baudRate = baudRate;
  590.         }
  591.     else
  592.         baudRate = globals->baudRate;
  593.  
  594.  
  595.     //    compute the divisor value to pop into the divisor latch registers
  596.  
  597.     divisor = (UInt16)(globals->UARTCrystalSpeed / baudRate / 16);
  598.  
  599.     USBSetBaudRateDivisor(divisor);
  600.     
  601.     //    return actual baud rate used
  602.  
  603.     return(globals->UARTCrystalSpeed / divisor / 16);
  604. }
  605.  
  606.  
  607.  
  608.  
  609. //////////////////////////////////////////////////////////////////////////////////////
  610. //
  611. //    B_SetParErrChar
  612. //
  613. //    assigns parity error replacement character and alternate replacment character.
  614. //    if peChar is zero then no parity error character substitution.
  615. //
  616. //
  617. void B_SetParErrChar(ShimSerialGlobals * globals, Boolean alt, char peChar, char peAltChar)
  618. {
  619. #pragma unused (globals, alt, peAltChar)
  620.  
  621.     USBSetParChar(peChar);
  622.  
  623. #ifdef NOTYET
  624.     //    by default, we clear high bit on any received
  625.     //    character matching the replacement character
  626.  
  627.     globals->peAltChar = peChar & 0x7F;
  628.  
  629.  
  630.     //    if alternate call, assign the alternate character
  631.  
  632.     if ( alt ) 
  633.         globals->peAltChar = peAltChar;
  634. #endif //NOTYET
  635. }
  636.  
  637.  
  638.  
  639. //////////////////////////////////////////////////////////////////////////////////////
  640. //
  641. //    B_FillReadRequest
  642. //
  643. //    for filling _Read requests.  attempts to copy requested bytes from internal serial
  644. //    buffer into request parameter block.  called from B_Read and B_UARTInput.
  645. //
  646. //
  647. OSErr B_FillReadRequest(ShimSerialGlobals * globals, IOParam * pb)
  648. {
  649.     OSErr                            result;
  650.     UInt16                            endIndex;
  651.     UInt16                            startIndex;
  652.  
  653.     result = 1;
  654.     while (result > noErr)
  655.         {
  656.  
  657.         //    this can be interrupted to add data to the internal buffer
  658.         //    so we update inBufStartIndex and inBufEndIndex each time
  659.         //    if there is nothing in the input buffer, leave quietly
  660.  
  661.         endIndex = globals->inBufEndIndex;
  662.         startIndex = globals->inBufStartIndex;
  663.         
  664.         if ( startIndex == endIndex ) 
  665.             break;
  666.  
  667.  
  668.         //    copy byte into read request buffer and bump actual count
  669.  
  670.         pb->ioBuffer[pb->ioActCount] = globals->inBufPtr[startIndex];
  671.         pb->ioActCount++;
  672.  
  673.  
  674.         //    now update internal buffer inBufStartIndex
  675.  
  676.         startIndex++;
  677.         
  678.         if ( startIndex >= globals->inBufLen ) 
  679.             startIndex = 0;
  680.             
  681.         globals->inBufStartIndex = startIndex;
  682.  
  683.  
  684.         //    lastly, check if we've satisfied the request
  685.  
  686.         if ( pb->ioReqCount <= pb->ioActCount )
  687.             result = noErr;
  688.         }
  689.  
  690.     return(result);
  691. }
  692.  
  693.  
  694.  
  695. #ifdef NOTNEEDED
  696.  
  697. //////////////////////////////////////////////////////////////////////////////////////
  698. //
  699. //    B_UARTInterrupt
  700. //
  701. //    this routine handles incoming interrupts from the uart.
  702. //
  703. //
  704. InterruptMemberNumber
  705. B_UARTInterrupt(InterruptSetMember ISTmember, void *refCon, UInt32 theIntCount)
  706. {
  707. #pragma unused (ISTmember)
  708. #pragma unused (refCon)
  709. #pragma unused (theIntCount)
  710.     UInt32    interruptIDMask;
  711.     Boolean    interruptHandled;
  712.     
  713.     
  714.     TraceMessage(1,"\pEntering B_UARTInterrupt");
  715.     
  716.     // Setup for spurious interrupt handling
  717.     interruptHandled = false;
  718.     
  719.     // While there is an interrupt service it.
  720.     do
  721.     {
  722.         // Get the value of the Interrupt Identification
  723.         // Register and mask off the important bits
  724.         interruptIDMask = (gGlobals->uartRegs->IIR) & kInterruptIDMask;
  725.         
  726.         // Since the bits of some values 'overlap' with others we must
  727.         // check the value as a single unit, which is actually OK because
  728.         // the UART will prioritize and only give us 1 interrupt at a time anyway.
  729.         switch(interruptIDMask)
  730.         {
  731.             case kModemStatusInterrupt:
  732.                 B_UARTModemStatus(gGlobals);
  733.                 interruptHandled = true;
  734.                 break;
  735.             
  736.             case kTXEmptyInterrupt:
  737.                 B_UARTOutput(gGlobals);
  738.                 interruptHandled = true;
  739.                 break;
  740.             
  741.             case kRXDataInterrupt:
  742.             case kRxStatusInterrupt:
  743.             case kCharTimeoutInterrupt:
  744.                 B_UARTInput(gGlobals);
  745.                 interruptHandled = true;
  746.                 break;
  747.             
  748.             case kNoInterrupt:
  749.             default:
  750.                 // We don't know what the interrupt was, or the UART
  751.                 // says we've serviced all pending interrupts...In
  752.                 // either case lets exit the interrupt handler because
  753.                 // we can no longer do any useful work.
  754.                 interruptIDMask = kNoInterrupt;
  755.                 break;
  756.         }
  757.         
  758.         // Continue processing interrupts until the UART
  759.         // gives us the 'no interrupts' pending signal
  760.     }while(interruptIDMask != kNoInterrupt);
  761.     
  762.     return interruptHandled ? kIsrIsComplete : kIsrIsNotComplete;
  763. }
  764.  
  765. #endif //NOTNEEDED
  766.  
  767. //////////////////////////////////////////////////////////////////////////////////////
  768. //
  769. //    B_UARTModemStatus
  770. //
  771. //    a modem status interrupt has been received.  we treat it here.
  772. //
  773. //
  774. void B_UARTModemStatus(ShimSerialGlobals * globals)
  775. {
  776.     unsigned char    modemStatus;
  777.     
  778.     TraceMessage(1,"\pEntering B_UARTModemStatus");
  779.     
  780.     modemStatus = USBGetModemStatus();
  781.     
  782.     //
  783.     //    if cts has changed, set ctsHold accordingly -- note this value is really
  784.     //    silly and just to placate clients that want this kind of status info --
  785.     //    we _always_ poll the modem status register to test cts during output
  786.     //
  787.  
  788.     if (modemStatus & kCTSChanged)
  789.     {
  790.         globals->serStat.ctsHold = !(modemStatus & kCTSCompliment);
  791.         B_EnableOutput(globals);
  792.     }
  793.     
  794.     //
  795.     //    should handle ring indicate here
  796.     //
  797.     return;
  798. }
  799.  
  800.  
  801.  
  802.  
  803.  
  804. #ifdef NOTNEEDED
  805. //////////////////////////////////////////////////////////////////////////////////////
  806. //
  807. //    B_UARTOutput
  808. //
  809. //    a modem transmit buffer empty interrupt has been received.  we treat it here.
  810. //
  811. //
  812. void B_UARTOutput(ShimSerialGlobals * globals)
  813. {
  814.     IOParam *                        pb;
  815.     volatile UART *                    uartRegs;
  816.     Ptr                                bufPtr;
  817.     OSErr                            result;
  818.     SInt16                            count;
  819.     
  820.     
  821.     TraceMessage(1,"\pEntering B_UARTOutput");
  822.     
  823.     //    set return result to incomplete
  824.     result = 1;
  825.     
  826.     //    pull out reference to uartRegs
  827.     //    (address validated by caller B_UARTInterrupt)
  828.     uartRegs = globals->uartRegs;
  829.     
  830.     //    if we are using fifos we can blast up to 16 bytes at the uart
  831.     count = (SInt16)((globals->useFIFO) ? 16 : 1);
  832.     
  833.     //    first handle any pending xon or xoff char to send
  834.     if ( globals->xOnOffChar )
  835.     {
  836.         //    write the xon or xoff character    
  837.         uartRegs->THR = globals->xOnOffChar;
  838.         globals->xOnOffChar = 0;
  839.         count--;
  840.     }
  841.     
  842.     //    pull out any pending write request
  843.     pb = (IOParam *)globals->pbOut;
  844.     if (pb)
  845.     {
  846.         //    are there still bytes to write?
  847.         if ( pb->ioActCount < pb->ioReqCount )
  848.         {
  849.             //    compute offset into the data buffer
  850.             bufPtr = pb->ioBuffer + pb->ioActCount;
  851.             
  852.             //    loop on fifo counter
  853.             while (count > 0)
  854.             {
  855.                 // Hardware output flow control check, if hardware flow control is
  856.                 // enabled and CTS is not asserted we must stop sending right now.
  857.                 if (gGlobals->serShk.fCTS && !(uartRegs->MSR & kCTSCompliment))
  858.                     break;
  859.                 
  860.                 //    write next byte into uart transmit register
  861.                 //    update buffer pointer & actual counter
  862.                 uartRegs->THR = *bufPtr++;
  863.                 pb->ioActCount++;
  864.                 count--;
  865.                 
  866.                 //    check if we have satisfied write request
  867.                 if ( pb->ioReqCount <= pb->ioActCount )
  868.                 {
  869.                     //    yes - set result and drop out of loop
  870.                     result = noErr;
  871.                     break;
  872.                 }
  873.             }
  874.         }
  875.         
  876.         //    if we have finished this write request, we
  877.         //    clear our local pb field before completion
  878.         //    to avoid any misunderstandings...
  879.         if ( result <= noErr ) 
  880.             globals->pbOut = nil;
  881.     }
  882.     
  883.     //    turn off write empty interrupts if we've no more data to send
  884.     B_EnableOutput(globals);
  885.     
  886.     // clean up after ourselves
  887.     if (result <= noErr)
  888.         ShimSerialStubIODone((union ParamBlockRec *)pb,*(globals->dceOut),result);
  889. }
  890.  
  891.  
  892.  
  893.  
  894. //////////////////////////////////////////////////////////////////////////////////////
  895. //
  896. //    B_UARTInput
  897. //
  898. //    this is the uart received data available interrupt service routine.  we loop on rx data
  899. //    ready bit set in the line status regiser, pulling the bytes from the receiver buffer
  900. //    register.  the rx data ready bit remains set as long as there are bytes to be read
  901. //    (i.e. still data available in the uart receive fifo, which holds up to 16 bytes)
  902. //    before returning check if there is an outstanding read and if so try to fill it.
  903. //
  904. //
  905. void B_UARTInput(ShimSerialGlobals * globals)
  906. {
  907.     volatile UART *                    uartRegs;
  908.     IOParam *                        pb;
  909.     OSErr                            result;
  910.     register UInt16                    nextIndex;
  911.     register unsigned char            rcvByte;
  912.     unsigned char                    lineStatus;
  913.     unsigned char                    newErrs;
  914.     unsigned char                    cumErrs;
  915.     
  916.         
  917.     TraceMessage(0,"\pEntering B_UARTInput");
  918.     
  919.     //    pull out reference to uartRegs
  920.     //    (address validated by caller B_UARTInterrupt)
  921.     
  922.     uartRegs = globals->uartRegs;
  923.     
  924.     //  this code will loop while there is data available in the uart receive buffer
  925.     //  it will also check for errors received via a kRxStatusInterrupt, since we
  926.     //  get called for kRxStatusInterrupt and kRXDataInterrupt.  A kRxStatusInterrupt
  927.     //  is just treated like a kRXDataInterrupt with no outstanding data.
  928.     
  929.     //    set return result to incomplete
  930.  
  931.     result = 1;
  932.     cumErrs = 0;
  933.  
  934.     do
  935.     {
  936.         //    pull out uart line status
  937.     
  938.         lineStatus = uartRegs->LSR;
  939.  
  940.         //  handle reading of data available in the uart receive buffer
  941.         
  942.         if ( lineStatus & kRxDataAvail )
  943.         {
  944.             //    then snatch the input character from the uart receive register
  945.             rcvByte = uartRegs->RBR;
  946.             
  947.             //    if software output flow control is enabled, check if this is an xon or xoff character
  948.             
  949.             if (    globals->serShk.fXOn && 
  950.                     (!(lineStatus & kRxErrMask)) &&
  951.                     (    (rcvByte == globals->serShk.xOn) || 
  952.                         (rcvByte == globals->serShk.xOff)))
  953.             {
  954.     
  955.                 //    set software output flow control based on xon or xoff received
  956.     
  957.                 globals->serStat.xOffHold = (rcvByte == globals->serShk.xOff);
  958.                 B_EnableOutput(globals);
  959.             }
  960.             else            
  961.             {
  962.                 //    else this is to be treated as a data byte for the client
  963.                 
  964.                 //    compute index into our input buffer
  965.     
  966.                 nextIndex = globals->inBufEndIndex + 1;
  967.                 if ( nextIndex >= globals->inBufLen ) 
  968.                     nextIndex = 0;
  969.                 
  970.                 //    check for parity error replacement character
  971.     
  972.                 if ( globals->peChar )
  973.                 {
  974.                     //    if parity error occured, replace the byte
  975.     
  976.                     if ( lineStatus & kParityErr ) 
  977.                     {
  978.                         rcvByte = globals->peChar;
  979.                     }
  980.                     else 
  981.                     {
  982.                         //    else if received byte matches replacement character, use alternate character
  983.     
  984.                         if ( rcvByte == globals->peChar ) 
  985.                             rcvByte = globals->peAltChar;
  986.                     }
  987.                 }
  988.     
  989.                 //    stuff the character into the input buffer and update the index
  990.     
  991.                 globals->inBufPtr[globals->inBufEndIndex] = rcvByte;
  992.                 globals->inBufEndIndex = nextIndex;
  993.     
  994.                 //    check for input buffer overflow
  995.     
  996.                 if ( globals->inBufEndIndex == globals->inBufStartIndex )
  997.                 {
  998.                     //    mark that we've had an overrun
  999.     
  1000.                     globals->serStat.cumErrs |= swOverrunErr;
  1001.                     cumErrs |= swOverrunErr;
  1002.                     
  1003.                     //    drop oldest character from our internal buffer
  1004.     
  1005.                     globals->inBufStartIndex++;
  1006.                     if ( globals->inBufStartIndex >= globals->inBufLen )
  1007.                         globals->inBufStartIndex = 0;
  1008.                     
  1009.                     //    we've had a software overrun -- rather than empty the uart
  1010.                     //    fifo and overwrite up to 16 bytes, we quit now and let the
  1011.                     //    client get a chance to read in the existing bytes -- if there
  1012.                     //    are still bytes pending in the fifo, we'll get interrupted
  1013.                     //    again real soon now...
  1014.                 }
  1015.             }
  1016.     
  1017.         }
  1018.  
  1019.         //    check for receive error condition
  1020.         //    for case of kRxStatusInterrupt with no data available
  1021.     
  1022.         if ( lineStatus & kRxErrMask )
  1023.         {
  1024.             //    mark error
  1025.     
  1026.             newErrs = 0;
  1027.             if ( lineStatus & kParityErr )         newErrs |= parityErr;
  1028.             if ( lineStatus & kOverrunErr )     newErrs |= hwOverrunErr;
  1029.             if ( lineStatus & kFramingErr )     newErrs |= framingErr;
  1030.             if ( lineStatus & kBreakDetect )     newErrs |= breakErr;
  1031.             globals->serStat.cumErrs |= newErrs;
  1032.             cumErrs |= newErrs;
  1033.         }
  1034.         
  1035.         //    check for an outstanding read request
  1036.         
  1037.         pb = (IOParam *)globals->pbIn;
  1038.         if (pb)
  1039.         {
  1040.             //    copy bytes from input buffer into pb read buffer
  1041.             //    (result is either 1=incomplete or 0=complete)
  1042.     
  1043.             result = B_FillReadRequest(globals, pb);
  1044.             
  1045.             //    handle errors that cause read aborts
  1046.             
  1047.             if ( cumErrs & globals->serShk.errs ) 
  1048.                 result = rcvrErr;
  1049.             
  1050.             //    if we have fulfilled this read request, we
  1051.             //  need to call IOCommandIsComplete and on it
  1052.             //  and continue processing with the next request
  1053.             
  1054.             if ( result <= noErr )
  1055.             {
  1056.                 globals->pbIn = nil;
  1057.                 break;
  1058.             }
  1059.         }
  1060.         
  1061.         
  1062.         //    handle hardware (dtr or rts) or software
  1063.         //    (xon / xoff) input flow control as necessary
  1064.         
  1065.         B_InputFlowControl(globals);
  1066.     
  1067.     //  loop while there is data available in the uart receive buffer
  1068.     
  1069.     }while(!(cumErrs & swOverrunErr) && (lineStatus & kRxDataAvail));
  1070.     
  1071.     // clean up after ourselves
  1072.     if (result <= noErr)
  1073.         ShimSerialStubIODone((union ParamBlockRec *)pb,*(globals->dceIn),result);
  1074. }
  1075.  
  1076. #endif //NOTNEEDED
  1077.  
  1078.  
  1079.  
  1080.  
  1081. //////////////////////////////////////////////////////////////////////////////////////
  1082. //
  1083. //    B_EnableSerialDevice
  1084. //
  1085. //    called once at driver open time to configure the uart, set baud rate, enable interrupts, etc.
  1086. //
  1087. //
  1088. void B_EnableSerialDevice(ShimSerialGlobals * globals)
  1089. {    
  1090.     
  1091.     TraceMessage(1,"\pEntering B_EnableSerialDevice");
  1092.     
  1093.     // TODO:  setup the device?
  1094.     
  1095.     // Setup Interrupt transaction to look for status changes (and update status global)
  1096.     
  1097.     B_EnableRTS(globals, 1);
  1098.     B_EnableDTR(globals, 1);
  1099.     B_SetBaudRate(globals, 0);
  1100.     B_SetLenParStop(globals, globals->lenParStop);
  1101.  
  1102.     USBSetControl(0);  // no flow control    
  1103.     // do we have to fire off a chained read to keep the buffers full?
  1104.     USBStartReadPolling();        
  1105.     
  1106. }
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112.  
  1113. //////////////////////////////////////////////////////////////////////////////////////
  1114. //
  1115. //    B_DisableSerialDevice
  1116. //
  1117. //    called once when the driver is closed to turn off modem interrupts
  1118. //
  1119. //
  1120. void B_DisableSerialDevice(ShimSerialGlobals * globals)
  1121. {
  1122. #pragma unused (globals)
  1123.     
  1124.     TraceMessage(1,"\pEntering B_DisableSerialDevice");
  1125.  
  1126.     USBStopReadPolling();
  1127.  
  1128.     B_EnableRTS(globals, 0);
  1129.     B_EnableDTR(globals, 0);
  1130. }
  1131.  
  1132.  
  1133.  
  1134.  
  1135.  
  1136.  
  1137. //////////////////////////////////////////////////////////////////////////////////////
  1138. //
  1139. //    B_InputFlowControl
  1140. //
  1141. //    handles hardware (dtr or rts) and software (xon / xoff) input flow control
  1142. //
  1143. //
  1144. void B_InputFlowControl(ShimSerialGlobals * globals)
  1145. {
  1146.     UInt32    threshold;
  1147.     SInt32    count;
  1148.     
  1149.     
  1150.     TraceMessage(0,"\pEntering B_InputFlowControl");
  1151.     
  1152.     //    compute threshold for flow control -- same algorithm as h&j
  1153.     count = globals->inBufEndIndex - globals->inBufStartIndex;
  1154.     
  1155.     if (count < 0) 
  1156.         count += globals->inBufLen;
  1157.     
  1158.     threshold = (4 * count) / globals->inBufLen;
  1159.  
  1160.     //    turn it off...
  1161.     if (threshold >= 3)
  1162.     {
  1163.         //    if hardware input flow control, turn it off now
  1164.         if (globals->serShk.fDTR && !(globals->serStat.xOffSent & dtrNegated))
  1165.             B_EnableInput(globals, false);
  1166.         
  1167.         //    if software (xon / xoff) input flow control
  1168.         //    and we've sent an xoff if we haven't already
  1169.         if ( globals->serShk.fInX ) 
  1170.             B_SendXOff(globals, false);
  1171.     }
  1172.     else 
  1173.     {
  1174.         if (threshold < 1)
  1175.         {
  1176.             //    ...or turn it on
  1177.             //    if hardware input flow control, turn it back on now
  1178.             if (globals->serShk.fDTR && (globals->serStat.xOffSent & dtrNegated))
  1179.                 B_EnableInput(globals, true);
  1180.             
  1181.             //    if software (xon / xoff) input flow control
  1182.             //    and we've sent an xoff we need to send an xon
  1183.             if ( globals->serShk.fInX ) 
  1184.                 B_SendXOn(globals, false);
  1185.         }
  1186.     }
  1187. }
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193. //////////////////////////////////////////////////////////////////////////////////////
  1194. //
  1195. //    B_EnableInput
  1196. //
  1197. //    we use the rts enable bit on the modem control register for dtr
  1198. //    we also use a variant introduced by the h&j driver of setting this
  1199. //    value in xOffSent of the serStat record -- doesn't seem to cause
  1200. //    any problems and a convenient place to track changes to dtr (or rts)
  1201. //
  1202. //
  1203. void B_EnableInput(ShimSerialGlobals * globals, Boolean enable)
  1204. {
  1205.     TraceMessage(1,"\pEntering B_EnableInput");
  1206.  
  1207.     if (enable)
  1208.     {
  1209. #ifdef NOTYET    
  1210.         globals->uartRegs->MCR |= kRTSEnable;
  1211. #endif //NOTYET
  1212.         globals->serStat.xOffSent &= ~dtrNegated; 
  1213.     }
  1214.     else
  1215.     {
  1216. #ifdef NOTYET    
  1217.         globals->uartRegs->MCR &= ~kRTSEnable;
  1218. #endif //NOTYET
  1219.         globals->serStat.xOffSent |= dtrNegated; 
  1220.     }
  1221. }
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227. //////////////////////////////////////////////////////////////////////////////////////
  1228. //
  1229. //    B_EnableOutput
  1230. //
  1231. //    this routine is the veritable on/off switch for transmission.  whenever you have
  1232. //    something to send or whenever you've finished sending something or whenever you
  1233. //    get the itch, just call this baby and it will check the state of everything and
  1234. //    turn on or off the "transmit buffer empty" interrupts on the card's uart.  when
  1235. //    those interrupts are enabled, our B_UARTOutput gets called, and we send, send,
  1236. //    send... until we can't send no more...  then we call this baby again and
  1237. //    turn those nasty persistent interrupts off...  clear as mud?
  1238. //
  1239.  
  1240. void B_EnableOutput(ShimSerialGlobals * globals)
  1241. {
  1242. #pragma unused (globals)
  1243.  
  1244.     TraceMessage(1,"\pEntering B_EnableOutput");
  1245.     
  1246.     // TODO:  ?
  1247.     
  1248. #ifdef NOTYET
  1249.     // The basic theory here is to check for the best flow control mechanism and work
  1250.     // backwards to the no flow control case.  If hardware flow control is enabled
  1251.     // and it says don't send, we will do nothing even if software flow control is also
  1252.     // enabled and it says send.  However, if hardware flow control isn't enabled then
  1253.     // software flow control gets to set the policy, and lastly if no flow control is
  1254.     // enabled we just enable output if we have data to send.
  1255.     
  1256.     // if ( hardware flow control enabled _and_ ( output is not suppressed _and_ we have something to output ))
  1257.     // _or_ if ( no hardware and we have software _and_ ( we have an xon or xoff char to send _or_ we have a write request _and_ output is not suppressed ))
  1258.     // _or_ if ( no hardware and no software _and_ we have something to output)
  1259.     if ((gGlobals->serShk.fCTS && ((gGlobals->uartRegs->MSR & kCTSCompliment) && globals->pbOut)) ||
  1260.         (!gGlobals->serShk.fCTS && globals->serShk.fXOn && (globals->xOnOffChar || (globals->pbOut && !globals->serStat.xOffHold))) ||
  1261.         (!gGlobals->serShk.fCTS && !globals->serShk.fXOn && globals->pbOut))
  1262.     
  1263.     {
  1264.         //    ...then turn on transmit buffer empty interrupts...
  1265.         globals->uartRegs->IER |= kTXEmptyIntEnable;
  1266.     }
  1267.     else
  1268.     {
  1269.         //    ...else turn them off
  1270.         globals->uartRegs->IER &= ~kTXEmptyIntEnable;
  1271.     }
  1272. #endif //NOTYET
  1273. }
  1274.